home *** CD-ROM | disk | FTP | other *** search
/ APDL Eductation Resources / APDL Eductation Resources.iso / programs / astronomy / skyview / !SkyView / c / TVSats < prev    next >
Encoding:
Text File  |  1993-08-26  |  16.5 KB  |  485 lines

  1. /********************************************************/
  2. /*               TVSats Module for SkyView              */
  3. /*                                                      */
  4. /*                  (c)1992 N P Hawkes                  */
  5. /*                                                      */
  6. /*         Displays geostationary TV satellites         */
  7. /********************************************************/
  8.  
  9. #include "menu.h"
  10. #include "dbox.h"
  11. #include "bbc.h"
  12. #include "wimpt.h"
  13. #include "dbox.h"
  14. #include "sprite.h"
  15. #include "res.h"
  16. #include "resspr.h"
  17. #include "werr.h"
  18.  
  19. #include "sv_header.h"
  20. #include "tvsats.h"
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <math.h>
  26. #include <ctype.h>
  27.  
  28. /********************************************************/
  29. /*                     Constants                        */
  30. /********************************************************/
  31. #define RHO 0.151             /* Ratio of Earth's radius*/
  32.                               /* to radius of geostat-  */
  33.                               /* ionary orbit.          */
  34. #define DISP_NAME "TV sats."  /* Entry in Display menu. */
  35. #define SEL_NAME  "TV sat."   /* Entry in Select menu.  */
  36.  
  37. #define MAX_SATS 25           /* Max no. of satellites. */
  38. #define FILE_NAME "SatData"   /* Name of data file.     */
  39.  
  40. #define FMT_LEN  256          /* Len. of format string. */
  41. #define NAME_LEN  15          /* Length of name field.  */
  42. #define DESC_LEN  30          /* Max len. of decsription*/
  43.  
  44. #define SPR_NAME "tvsat"      /* Name of sprite.        */
  45. #define SPR_X0 -12            /* Bounding box of        */
  46. #define SPR_Y0 -12            /* sprite, OS units,      */
  47. #define SPR_X1  14            /* relative to            */
  48. #define SPR_Y1  14            /* plotting position.     */
  49. #define SPR_COL  5            /* Sprite x offset.       */
  50. #define SPR_ROW  4            /* Sprite y offset.       */
  51. #define SPR_MODE MODE_20      /* Sprite mode.           */
  52.  
  53. /********************************************************/
  54. /*                New types of variable.                */
  55. /********************************************************/
  56. /* Structure describing one satellite.                  */
  57. typedef struct {
  58.   char name[NAME_LEN+1];  /* Name of satellite.         */
  59.   REAL longit;            /* Longitude of satellite.    */
  60.   char descr[DESC_LEN+1]; /* Description.               */
  61.   int  horiz_id;          /* id in Horiz window.        */
  62.   int  vert_id;           /* id in Vert window.         */
  63. } satstr;
  64.  
  65. /********************************************************/
  66. /*                  Global Variables                    */
  67. /********************************************************/
  68. static BOOL display_flag = FALSE;  /* 'Enabled' flag.   */
  69. static int moduleid;               /* Module ID.        */
  70.  
  71. static FILE *fileptr;              /* Ptr to data file. */
  72. static char fmt[FMT_LEN];          /* For format string.*/
  73. static satstr sat_data[MAX_SATS];  /* Main data store.  */
  74. static int sat_count = 0;          /* No. of satellites.*/
  75.  
  76. static menu sat_menu;  /* For selecting a satellite.    */
  77.  
  78. static double cos_anglimit = RHO;
  79. /* Satellite is below horizon if cos of angle between   */
  80. /* vector to it and vector to observer is less than     */
  81. /* cos_anglimit (where origin is centre of Earth).      */ 
  82.  
  83. static double delta;   /* For diff between longitude of */
  84.                        /* observer & that of satellite. */
  85. static double dlatit;  /* Double version of latitude of */
  86.                        /* observer.                     */
  87. static double cosbeta; /* For cosine of angle OCS, where*/
  88.                        /* O=observer, C=centre of earth,*/
  89.                        /* S=satellite.                  */
  90.  
  91. static sprite_id spr_id;  /* ID of satellite sprite.    */
  92.  
  93. /********************************************************/
  94. /*                 Function Prototypes                  */
  95. /********************************************************/
  96. static void tvsats_buildfn(void);
  97. static void tvsats_selectfn(selectfn_reasoncode reason);
  98. static BOOL tvsats_displayfn(BOOL *enabptr);
  99. static os_error *tvsats_plotfn(int x, int y, int id);
  100. static void tvsats_infofn(int id);
  101. static BOOL read_satdata(satstr *sptr);
  102. static char *trim(char *str);
  103. static void tvsat_altaz(int id, REAL *altptr, REAL *azimptr);
  104. static void read_optional(char *string, int count);
  105.  
  106. /********************************************************/
  107. /*                Initialisation Function               */
  108. /********************************************************/
  109. BOOL tvsats_initfn(int moduleno, modulestr *tvsats)
  110. {
  111.   int i;
  112.   sprite_id nametype_id;
  113.   os_error *errptr;
  114.  
  115. /* Record the module number of this module.             */
  116.   moduleid = moduleno;
  117.  
  118. /* Open data file.                                      */
  119.   fileptr = res_openfile(FILE_NAME, "r");
  120.   if (fileptr==NULL) return FALSE;
  121.  
  122. /* Construct the format string for reading the data.    */
  123.   sprintf(fmt, "%%%ic%%f %%c", NAME_LEN);
  124.  
  125. /* Read data, one satellite at a time.  Stop on first   */
  126. /* error (probably EOF).  Stay within array bounds.     */
  127.   while (sat_count < MAX_SATS && \
  128.          read_satdata(&sat_data[sat_count]))
  129.     sat_count++;
  130.  
  131. /* Close file.  Fatal error if it won't close.          */
  132.   if (fclose(fileptr) != 0)
  133.     werr(FATAL, "TVSats Error: Can't close Data file");
  134.  
  135. /* Quit if no items have been read.                     */
  136.   if (sat_count == 0) return FALSE;
  137.  
  138. /* Build menu for Select function.                      */
  139. /* Use menu_new for first item, menu_extend thereafter. */
  140.   sat_menu = menu_new(SEL_NAME ":", sat_data[0].name);
  141.   if (sat_menu == NULL) return FALSE;
  142.   for (i=1; i<sat_count; i++)
  143.     menu_extend(sat_menu, sat_data[i].name);
  144.  
  145. /* Fill in the fields of the modulestr.                 */
  146.   tvsats->buildfn  = tvsats_buildfn;
  147.   tvsats->selectfn = tvsats_selectfn;
  148.   tvsats->dispfn   = tvsats_displayfn;
  149.   tvsats->infofn   = tvsats_infofn;
  150.   tvsats->initial  = display_flag;
  151.   tvsats->display_entry = DISP_NAME;
  152.   tvsats->display_menu  = NULL;
  153.   tvsats->select_entry  = SEL_NAME;
  154.   tvsats->select_menu   = sat_menu;
  155.  
  156. /* Set up the sprite_id structure which identifies the  */
  157. /* satellite sprite.                                    */
  158. /* First set up a name-type identifier.                 */
  159.   nametype_id.s.name = SPR_NAME;
  160.   nametype_id.tag    = sprite_id_name;
  161. /* Then get the address of the sprite, and put it in    */
  162. /* the global sprite identifier spr_id.                 */
  163.   errptr = sprite_select_rp(resspr_area(), &nametype_id, &spr_id.s.addr);
  164.   if (errptr != NULL) return FALSE;
  165. /* Finally tag the identifier spr_id as address-type.  */
  166.   spr_id.tag = sprite_id_addr;
  167.  
  168.   return TRUE;
  169. }
  170.  
  171. /*------------------------------------------------------*/
  172. /*    Function to read in a line of satellite data.     */
  173. /*  Name, longitude and E/W designator must be present. */
  174. /*                Description is optional.              */
  175. /*  Return TRUE if at least the minimum data have been  */
  176. /*          sucessfully read, FALSE otherwise.          */
  177. /*------------------------------------------------------*/
  178. static BOOL read_satdata(satstr *sptr)
  179. {
  180.   /* Temp storage for sat's longitude (in float form):  */
  181.   float flongit;
  182.   /* Temp storage for char which designates E or W:     */
  183.   char ew;
  184.  
  185. /* Read name, longitude, and E/W.                       */
  186. /* Return FALSE if error (probably EOF) occurs.         */
  187.   if (fscanf(fileptr, fmt,
  188.              sptr->name,
  189.              &flongit,
  190.              &ew)
  191.                  != 3)
  192.     return FALSE;
  193.  
  194. /* Put a terminating \0 into the name string.  Then     */
  195. /* trim trailing blanks.                                */
  196.   sptr->name[NAME_LEN] = '\0';
  197.   trim(sptr->name);
  198.  
  199. /* Convert longit to radians. <0 if East.               */
  200.   if (ew == 'E' || ew == 'e') flongit = -flongit;
  201.   sptr->longit = (REAL)flongit * CONV;
  202.  
  203. /* Read description, if it is present.                  */
  204. /* Trim any trailing blanks.                            */
  205.   read_optional(sptr->descr, DESC_LEN);
  206.   trim(sptr->descr);
  207.  
  208.   return TRUE;
  209. }
  210.  
  211. /*------------------------------------------------------*/
  212. /* Function which reads optional description string at  */
  213. /* end of current line.  Reads at most 'count' chars.   */
  214. /* Returns null string if description is absent.        */
  215. /*------------------------------------------------------*/
  216. static void read_optional(char *string, int count)
  217. {
  218.   int c;
  219.  
  220. /* Skip any leading white space (except '\n').          */
  221.   do
  222.     c = fgetc(fileptr);
  223.   while (isspace(c) && c != '\n');
  224.  
  225. /* Read characters into string until:                   */
  226. /*      'count' chars have been read in,                */
  227. /* or   \n is seen (in which case do not store \n),     */
  228. /* or   EOF is seen.                                    */
  229.   while (count>0  &&  c!='\n'  &&  c!=EOF)
  230.   {
  231.     *string++ = c;
  232.     count--;
  233.     c = fgetc(fileptr);
  234.   }
  235.  
  236. /* Add terminating \0.                                  */
  237.   *string = '\0';
  238.  
  239. /* If neither \n or EOF was seen, discard remainder     */
  240. /* of current line.                                     */
  241.   while (c!='\n' && c!=EOF) c = fgetc(fileptr);
  242.  
  243.   return;
  244. }
  245.  
  246. /*------------------------------------------------------*/
  247. /*  Function which trims trailing blanks from a string. */
  248. /*------------------------------------------------------*/
  249. static char *trim(char *str)
  250. {
  251.   char *ptr;
  252.  
  253.   for (ptr = str+strlen(str); ptr>str && *(ptr-1)==' '; ptr--)
  254.     ;
  255.   *ptr = '\0';
  256.  
  257.   return str;
  258. }
  259. /********************************************************/
  260. /*                 List-Building Function               */
  261. /********************************************************/
  262. static void tvsats_buildfn(void)
  263. {
  264.   int i;
  265.   plotobj tvsat;
  266.  
  267.   /* Bounding box of plotting symbol, relative to       */
  268.   /* position of symbol:                                */
  269.   static wimp_box size = {SPR_X0, SPR_Y0, SPR_X1, SPR_Y1};
  270.  
  271. /* For each satellite in turn:                          */
  272.   for (i=0; i<sat_count; i++)
  273.   {
  274.  
  275.     /* Calculate cosine of angle OCS (Observer, Centre  */
  276.     /* of earth, Satellite).                            */
  277.     delta = (double)ob_data.longit - (double)sat_data[i].longit;
  278.     dlatit= (double)ob_data.latit;
  279.     cosbeta = cos(dlatit)*cos(delta);
  280.     if (cosbeta >  1.0) cosbeta =  1.0;
  281.     if (cosbeta < -1.0) cosbeta = -1.0;
  282.     
  283.     /* See if satellite is below the horizon, by        */
  284.     /* comparing cosbeta with limit.                    */
  285.     if (cosbeta < cos_anglimit)
  286.     {
  287.       /* Do not bother to offer this one to main program*/
  288.       /* Just set horiz and vert ids to NOWHERE, and    */
  289.       /* continue with next satellite.                  */
  290.       sat_data[i].horiz_id = NOWHERE;
  291.       sat_data[i].vert_id  = NOWHERE;
  292.       continue;
  293.     }
  294.  
  295.     /* Build plotobj.                                   */
  296.     tvsat.id = i;
  297.     tvsat.module = moduleid;
  298.     tvsat.plotfn  = tvsats_plotfn;
  299.     tvsat_altaz(i, &tvsat.alt, &tvsat.azim);
  300.     tvsat.size = size;
  301.  
  302.     /* Offer this to the main program.                  */
  303.     addobj(tvsat, &sat_data[i].horiz_id, &sat_data[i].vert_id);
  304.  
  305.   }
  306.  
  307.   return;
  308. }
  309.  
  310. /*------------------------------------------------------*/
  311. /*   Function to calculate alt & azim of satellite i.   */
  312. /*------------------------------------------------------*/
  313. static void tvsat_altaz(int id, REAL *altptr, REAL *azimptr)
  314. {
  315. /* Assumes delta, dlatit and cosbeta are already valid  */
  316. /* for this satellite.                                  */
  317.  
  318.   double sinbeta;
  319.   double cosalt, alt, cosazim, azim;
  320.   static double epsilon = 8.7E-04;
  321.  
  322. /* Special case when observer is almost directly       */
  323. /* beneath satellite.                                  */
  324.   if (fabs(delta) < epsilon && fabs(dlatit) < epsilon)
  325.   {
  326.     *altptr  = PIby2;
  327.     *azimptr = (REAL)0.0;
  328.     return;
  329.   }
  330.  
  331.   sinbeta = sin(acos(cosbeta));
  332.  
  333.   cosalt  = sinbeta/sqrt(1.0+RHO*RHO-2.0*RHO*cosbeta);
  334.   if (cosalt >  1.0) cosalt =  1.0;
  335.   if (cosalt < -1.0) cosalt = -1.0;
  336.   cosazim = -tan(dlatit)*cosbeta/sinbeta;
  337.   if (cosazim >  1.0) cosazim =  1.0;
  338.   if (cosazim < -1.0) cosazim = -1.0;
  339.  
  340.   alt  = acos(cosalt);
  341.   azim = (delta >= 0 ? acos(cosazim): -acos(cosazim));
  342.  
  343.   *altptr = (REAL)alt;
  344.   *azimptr= (azim >= 0 ? (REAL)azim: (REAL)2.0*PI + (REAL)azim);
  345.  
  346.   return;
  347. }
  348.  
  349.   
  350. /********************************************************/
  351. /*              Object-Selecting Function               */
  352. /********************************************************/
  353. static void tvsats_selectfn(selectfn_reasoncode reason)
  354. {
  355.   int menu_hit, sat_id;
  356.   REAL sat_longit;
  357.  
  358.   switch (reason)
  359.   {
  360.     case new_selection:
  361.       /* Look at list of menu hits to find which        */
  362.       /* satellite is to be selected.                   */
  363.       menu_hit = module_submenu_hits[0];
  364.  
  365.       /* If no hits on Satellite menu, flag the failure */
  366.       /* and return.  Also return if hit is off the end.*/
  367.       if (menu_hit <= 0 || menu_hit > sat_count)
  368.       {
  369.         selection.selected_OK = FALSE;
  370.         return;
  371.       }
  372.         
  373.       /* Fill in Selection details for requested        */
  374.       /* satellite.  Allow for menu entries being       */
  375.       /* indexed from 1 instead of 0.                   */
  376.       sat_id = menu_hit - 1;
  377.       selection.id          = sat_id;
  378.       selection.selected_OK = TRUE;
  379.       selection.horiz_id    = sat_data[sat_id].horiz_id;
  380.       selection.vert_id     = sat_data[sat_id].vert_id;
  381.       selection.now         = selection.horiz_id != NOWHERE || \
  382.                               selection.vert_id  != NOWHERE;
  383.       selection.rising      = FALSE;
  384.       selection.setting     = FALSE;
  385.       selection.culminating = FALSE;
  386.       break;
  387.  
  388.     case window_selection:
  389.       /* Inspect id field to find out which satellite   */
  390.       /* is to be selected.                             */
  391.       sat_id = selection.id;
  392.       selection.horiz_id    = sat_data[sat_id].horiz_id;
  393.       selection.vert_id     = sat_data[sat_id].vert_id;
  394.       selection.now         = selection.horiz_id != NOWHERE || \
  395.                               selection.vert_id  != NOWHERE;
  396.       selection.rising      = FALSE;
  397.       selection.setting     = FALSE;
  398.       selection.culminating = FALSE;
  399.       break;
  400.  
  401.     case recalculate_data:
  402.       /* Observer details have changed, and plotting    */
  403.       /* lists have been rebuilt. Update Selection data.*/
  404.       sat_id = selection.id;
  405.       selection.horiz_id    = sat_data[sat_id].horiz_id;
  406.       selection.vert_id     = sat_data[sat_id].vert_id;
  407.       selection.now         = selection.horiz_id != NOWHERE || \
  408.                               selection.vert_id  != NOWHERE;
  409.       break;
  410.  
  411.     case timeonly_recalculate:
  412.       /* As above, but only the time of day (and        */
  413.       /* possibly the direction of view - this is of no */
  414.       /* interest) have changed.                        */
  415.       sat_id = selection.id;
  416.       selection.horiz_id    = sat_data[sat_id].horiz_id;
  417.       selection.vert_id     = sat_data[sat_id].vert_id;
  418.       break;
  419.  
  420.     case sel_info_request:
  421.       /* Write info into text buffer.                   */
  422.       sat_id = selection.id;
  423.       sat_longit = sat_data[sat_id].longit/CONV;
  424.       sprintf(infoptr,"%s%s%s%.1f%s%s%s%s%s",
  425.       "TV Satellite (Geostationary)\n",
  426.       sat_data[sat_id].name, "\n",
  427.       fabs((double)sat_longit),"° ",
  428.       (sat_longit>0? "W\n" : "E\n"),
  429.       sat_data[sat_id].descr,"\n",
  430.       (selection.now? "Always visible from here": 
  431.                       "Never visible from here"));
  432.       break;
  433.  
  434.     default:
  435.       /* Unknown option.  Do nothing.                   */
  436.       break;
  437.  
  438.     }
  439.  
  440.   return;
  441. }
  442.  
  443.  
  444. /********************************************************/
  445. /*                   Display Function                   */
  446. /********************************************************/
  447. static BOOL tvsats_displayfn(BOOL *enabptr)
  448. {
  449. /* Toggle Enable/Disable flag.                          */
  450.   display_flag = !display_flag;
  451.  
  452. /* Inform main program of new status.                   */
  453.   *enabptr = display_flag;
  454.  
  455. /* Windows will always need updating.                   */
  456.   return TRUE;
  457. }
  458.  
  459.  
  460. /********************************************************/
  461. /*                   Plotting Function                  */
  462. /********************************************************/
  463. static os_error *tvsats_plotfn(int x, int y, int id)
  464. {
  465.   return sv_plotsprite(&spr_id, SPR_MODE, x, y, SPR_COL, SPR_ROW);
  466. }
  467.  
  468.  
  469. /********************************************************/
  470. /*                     Info Function                    */
  471. /********************************************************/
  472. static void tvsats_infofn(int id)
  473. {
  474.   REAL longit = sat_data[id].longit/CONV;
  475.  
  476.   sprintf(infoptr,"%s%s%s%.1f%s%s%s",
  477.                   "TV Satellite (Geostationary)\n",
  478.                    sat_data[id].name, "\n",
  479.                    fabs((double)longit),"° ",
  480.                    (longit>0? "W\n" : "E\n"),
  481.                    sat_data[id].descr);
  482.  
  483.   return;
  484. }
  485.